﻿using System;
using System.Linq;
using CrmClient.Linq;
using CrmClient.Mapping;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using System.Linq.Expressions;

namespace MsCrmClientTest
{
    [EntityLogicalName("connectionrole_category")]
    public class ConnectionRoleCategoryEnum : CrmOptionsSetBase
    { }

    [EntityLogicalNameAttribute("businessunit")]
    public class CrmDivision : CrmDataContractBase
    {
        [AttributeLogicalNameAttribute("businessunitid")]
        public override Guid Id { get; set; }
        [AttributeLogicalNameAttribute("name")]
        public string Name { get; set; }
    }

    [EntityLogicalNameAttribute("systemuser")]
    public class CrmUser : CrmDataContractBase
    {
        [AttributeLogicalNameAttribute("systemuserid")]
        public override Guid Id { get; set; }
        [AttributeLogicalNameAttribute("fullname")]
        public string Name { get; set; }
        [AttributeLogicalNameAttribute("parentsystemuserid")]
        public EntityReference Director { get; set; }
        [AttributeLogicalNameAttribute("businessunitid")]
        public EntityReference Division { get; set; }
    }

    [EntityLogicalNameAttribute("new_nsi")]
    public class NSI : CrmDataContractBase
    {
        [AttributeLogicalNameAttribute("new_nsiid")]
        public override Guid Id { get; set; }

        [AttributeLogicalNameAttribute("new_name")]
        public string Name { get; set; }

        [AttributeLogicalNameAttribute("ownerid")]
        public EntityReference Owner { get; set; }

        [AttributeLogicalNameAttribute("new_bank")]
        public decimal Bank { get; set; }

        [AttributeLogicalNameAttribute("new_margin")]
        public decimal Margin { get; set; }

        [AttributeLogicalNameAttribute("new_corpnalog")]
        public int Corpnalog { get; set; }

        [AttributeLogicalNameAttribute("new_nds")]
        public decimal WAT { get; set; }

        [AttributeLogicalNameAttribute("new_workcost")]
        public int Workcost { get; set; }

    }

    public class TestUser
    {
        public Guid Id { get; set; }
        public string FullName { get; set; }
        public EntityReference Director { get; set; }
        public int Test { get; set; }
    }

    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class Test
    {
        private static OrgCrmClient _client;

        private static Guid _directorUserId = Guid.Parse("4d9235f1-9908-e211-a36c-080027e7a29a");

        [ClassInitialize()]
        public static void ClassInit(TestContext context)
        {
            _client = new OrgCrmClient();
        }

        [ClassCleanup()]
        public static void ClassCleanup()
        {
            _client.Dispose();
            _client = null;
        }

        [TestMethod]
        public void TestOptionsSet()
        {
            var optionSet = _client.OptionsSet<ConnectionRoleCategoryEnum>();
        }

        [TestMethod]
        public void TestQuery()
        {
            var users = _client.Query<CrmUser>().ToList();
            Assert.IsTrue(users.Count > 0);
        }

        [TestMethod]
        public void TestDistinct()
        {
            var users = _client.Query<CrmUser>()
                .CrmDistinct()
                .ToList();
            Assert.IsTrue(users.Count == users.Distinct().Count());
        }

        [TestMethod]
        public void TestNoLock()
        {
            var users = _client.Query<CrmUser>()
                .CrmNoLock()
                .ToList();
        }

        [TestMethod]
        public void TestWhere()
        {
            var user = _client.Query<CrmUser>()
                .CrmWhere(i => i.Id == _directorUserId)
                .ToList();
            Assert.IsTrue(user.Count == 1);

            var users = _client.Query<CrmUser>().ToList();
            var directors = users.Where(u => u.Director != null).Select(u => new { u.Director.Id, u.Director.Name }).Take(2);
            var users2 = _client.Query<CrmUser>()
                .CrmWhere(ExpressionType.Or, directors, (u, d) => u.Id == d.Id && u.Name == d.Name, (pn, o) =>
                    {
                        switch (pn)
                        {
                            case "Id":
                                return o.Id;
                            case "Name":
                                return o.Name;
                            default:
                                return null;
                        }
                    })
                .ToList();
            Assert.IsTrue(users2.Count == 2);
        }

        [TestMethod]
        public void TestOrder()
        {
            var users = _client.Query<CrmUser>()
                .CrmOrderBy(i => i.Name)
                .CrmOrderByDescending(i => i.Id)
                .ToList();
            Assert.IsTrue(users.Count > 0);
        }

        [TestMethod]
        public void TestPaging()
        {
            int total;
            bool moreExists;
            var users = _client.Query<CrmUser>()
                .CrmGetPage(1, 10, out total, out moreExists);
            Assert.IsTrue(users.Count == 10);
            Assert.IsTrue(total > 0);
            Assert.IsTrue(moreExists);
        }

        [TestMethod]
        public void TestSelect()
        {
            var users = _client.Query<CrmUser>()
                .CrmSelect(u => new
                {
                    u.Id,
                    FullName = u.Name,
                    Test = 1
                })
                .ToList();
            Assert.IsTrue(users.Count > 0);

            var users2 = _client.Query<CrmUser>()
                .CrmSelect(u => new TestUser()
                {
                    Id = u.Id,
                    FullName = u.Name,
                    Test = 1
                })
                .ToList();
            Assert.IsTrue(users2.Count > 0);
        }

        [TestMethod]
        public void TestJoin()
        {
            var users = _client.Query<CrmUser>()
                .CrmJoin(_client.Query<CrmUser>(), s => s.Director.Id, d => d.Id, (s, d) => new { s.Id, FullName = s.Name, DirectorId = d.Id, DirectorFullName = d.Name })
                .ToList();
            Assert.IsTrue(users.Count > 0);

            users = _client.Query<CrmUser>()
                .CrmLeftJoin(_client.Query<CrmUser>(), s => s.Director.Id, d => d.Id, (s, d) => new { s.Id, FullName = s.Name, DirectorId = d.Id, DirectorFullName = d.Name })
                .ToList();
            Assert.IsTrue(users.Count > 0);
        }

        [TestMethod]
        public void TestJoinWithFilter()
        {
            var users = _client.Query<CrmUser>()
                .CrmJoin(_client.Query<CrmUser>().CrmWhere(u => u.Id == _directorUserId), s => s.Director.Id, d => d.Id, (s, d) => new { s.Id, FullName = s.Name, DirectorId = d.Id, DirectorFullName = d.Name })
                .ToList();
            Assert.IsTrue(users.Count > 0);

            users = _client.Query<CrmUser>()
                .CrmLeftJoin(_client.Query<CrmUser>().CrmWhere(u => u.Id == _directorUserId), s => s.Director.Id, d => d.Id, (s, d) => new { s.Id, FullName = s.Name, DirectorId = d.Id, DirectorFullName = d.Name })
                .ToList();
            Assert.IsTrue(users.Count > 0);
        }

        [TestMethod]
        public void TestIn()
        {
            var users = _client.Query<CrmUser>().ToList();
            var list = new[] { _directorUserId };

            var filteredUsers = _client.Query<CrmUser>()
               .CrmWhere(i => list.Contains(i.Id))
               .ToList();
            Assert.IsTrue(filteredUsers.Count == 1);

            filteredUsers = _client.Query<CrmUser>()
               .CrmWhere(i => !list.Contains(i.Id))
               .ToList();
            Assert.IsTrue(filteredUsers.Count == users.Count - 1);
        }

        [TestMethod]
        public void TestLike()
        {
            var users = _client.Query<CrmUser>().ToList();
            var firstUser = users.First(i => i.Name.Contains(" ")).Name.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            var user = _client.Query<CrmUser>()
                .CrmWhere(i => i.Name.StartsWith(firstUser[0]))
                .ToList();
            Assert.IsTrue(user.Count == 1);

            user = _client.Query<CrmUser>()
                .CrmWhere(i => i.Name.EndsWith(firstUser[0]))
                .ToList();
            Assert.IsTrue(user.Count == 0);

            user = _client.Query<CrmUser>()
                .CrmWhere(i => i.Name.Contains(firstUser[0]))
                .ToList();
            Assert.IsTrue(user.Count == 1);


            user = _client.Query<CrmUser>()
                .CrmWhere(i => !i.Name.StartsWith(firstUser[0]))
                .ToList();
            Assert.IsTrue(user.Count > 0);

            user = _client.Query<CrmUser>()
                .CrmWhere(i => !i.Name.EndsWith(firstUser[0]))
                .ToList();
            Assert.IsTrue(user.Count > 0);

            user = _client.Query<CrmUser>()
                .CrmWhere(i => !i.Name.Contains(firstUser[0]))
                .ToList();
            Assert.IsTrue(user.Count > 0);

        }

        [TestMethod]
        public void TestCUD()
        {
            var nsi = _client.Query<NSI>().First();
            var newnsi = new NSI { Owner = nsi.Owner, Bank = 0, Corpnalog = 0, Margin = 0, WAT = 0, Workcost = 0, Name = "Test NSI" };

            _client.Add(newnsi);
            Assert.IsTrue(newnsi.Id != Guid.Empty);

            newnsi.WAT = 1;
            _client.Update(newnsi);
            var updatedNSI = _client.Query<NSI>().CrmWhere(u => u.Id == newnsi.Id).Single();
            Assert.IsTrue(updatedNSI.WAT == 1);

            _client.Delete(newnsi);
            var deletedNSI = _client.Query<NSI>().CrmWhere(u => u.Id == newnsi.Id).FirstOrDefault();
            Assert.IsTrue(deletedNSI == null);
        }
    }
}
